package taskhandler

import (
	"fmt"
	"strings"
	"time"

	"cvevulner/common"
	"cvevulner/models"
	"cvevulner/util"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
)

type GiteeTokenInfo struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int64  `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
	Scope        string `json:"scope"`
	CreatedAt    int64  `json:"created_at"`
}

// Verify whether the issue on gitee is deleted, and the specific logic is implemented
func ProcIssueIsExists(prnum int) error {
	cveId := int64(0)
	for {
		vc, err := models.QueryAllCveVuln(prnum, cveId)
		if err != nil {
			logs.Error("QueryAllCveVuln, err: ", err)
			break
		}
		if len(vc) == 0 {
			break
		}
		for _, v := range vc {
			cveId = v.CveId
			issueTmp := models.IssueTemplate{CveId: v.CveId, Repo: v.PackName, CveNum: v.CveNum}
			tempErr := models.GetIssueTemplateByColName(&issueTmp, "CveId", "Repo", "CveNum")
			if tempErr != nil {
				continue
			}
			if issueTmp.IssueNum != "" && len(issueTmp.IssueNum) > 0 {
				issueErr := error(nil)
				issueData := map[string]interface{}{}
				path := issueTmp.Repo
				owner, accessToken := common.GetOwnerAndToken(v.CveNum, v.OrganizationID)
				if v.OrganizationID == 2 {
					if len(path) < 2 {
						path = beego.AppConfig.String("opengauss::gauss_issue_path")
					}
				}
				issueErr, issueData = GetGiteeIssue(accessToken, owner, path, issueTmp.IssueNum)
				if issueErr != nil {
					logs.Info("UpdateIssueTemplate1, issueNum: ", issueTmp.IssueNum, issueTmp.StatusName)
					issueTmp.Status = 6
					issueTmp.StatusName = "deleted"
					issueTmp.DeleteTime = time.Now()
					updateErr := models.UpdateIssueTemplate(&issueTmp, "Status", "StatusName", "DeleteTime")
					if updateErr != nil {
						logs.Error("UpdateIssueTemplate1, err: ", updateErr)
					}
				} else {
					if issueData != nil && issueData["state"] != nil && issueData["state"].(string) != "" {
						state := issueData["state"].(string)
						if state == "待办的" || state == "开启的" ||
							strings.ToLower(state) == "open" {
							issueTmp.StatusName = "open"
							issueTmp.Status = 1
						} else if state == "进行中" || strings.ToLower(state) == "started" ||
							strings.ToLower(state) == "progressing" {
							issueTmp.StatusName = "progressing"
							issueTmp.Status = 2
						} else if state == "已完成" || strings.ToLower(state) == "closed" {
							issueTmp.StatusName = "closed"
							issueTmp.IssueLabel = beego.AppConfig.String("labelFixed")
							issueTmp.Status = 3
						} else if state == "已拒绝" || strings.ToLower(state) == "rejected" {
							issueTmp.StatusName = "rejected"
							issueTmp.Status = 4
						} else if state == "已挂起" || strings.ToLower(state) == "suspended" {
							issueTmp.StatusName = "suspended"
							issueTmp.Status = 5
						} else {
							issueTmp.StatusName = state
						}
						if issueData["issue_state"] != nil && issueData["issue_state"].(string) != "" {
							issueState := issueData["issue_state"].(string)
							if issueState == "已挂起" || strings.ToLower(issueState) == "suspended" {
								issueTmp.StatusName = "suspended"
								issueTmp.Status = 5
							}
						}
						logs.Info("UpdateIssueTemplate2, issueNum: ", issueTmp.IssueNum, issueTmp.StatusName)
						updateErr := models.UpdateIssueTemplate(&issueTmp, "Status", "StatusName", "IssueLabel")
						if updateErr != nil {
							logs.Error("UpdateIssueTemplate2, err: ", updateErr)
						}
					}
				}
			}
		}
	}
	return nil
}

// Statistics on the creation of openEuler community issues
// Statistics on the creation of openGauss community issues
// Statistics on the creation of issues in the MindSpore community
func StatistCommunityIssue(cyc models.CommunityYamlConfig) {
	// cve credibility level
	credibilityLevel, ok := beego.AppConfig.Int("cve::credibility_level")
	if ok != nil {
		logs.Error("cve::credibility_level, err:", ok)
		credibilityLevel = 3
	}
	id := int64(0)
	count := 50
	for {
		communityPackage := models.GetCommunityYamlList(cyc.TableName, id, count)
		if len(communityPackage) > 0 {
			for _, cpg := range communityPackage {
				id = cpg.Id
				if cyc.OrganizationID == 1 && len(cpg.RepoName) < 1 {
					cpg.RepoName = cpg.PackageName
				}
				ous := models.QueryOriginUpstreamByName(cpg.PackageName, credibilityLevel)
				CheckOriginUpstreamToCenter(ous, cpg.PackageName, cpg.RepoName, cpg.PackageVersion, cyc.OrganizationID)
			}
		} else {
			break
		}
	}
}

func CheckOriginUpstreamToCenter(ous []models.OriginUpstream,
	packageName, repoName, packageVersion string, organizationID int8) {
	for _, ou := range ous {
		ics := models.IssueCommunityStatistics{CveNum: ou.CveNum, Repo: repoName, ExistFlag: organizationID}
		queryErr := models.QueryIssueCommunityStatistics(&ics, "CveNum", "Repo", "ExistFlag")
		if ics.Id > 0 {
			continue
		} else {
			logs.Info("QueryIssueCommunityStatistics, queryErr: ", queryErr)
		}
		packNameMap := map[string]string{}
		packNameList := []string{}
		if len(ou.PackName) > 0 {
			packNameList = strings.Split(ou.PackName, ",")
			if len(packNameList) > 0 {
				for _, pk := range packNameList {
					pkList := strings.Split(pk, "==")
					if len(pkList) == 2 {
						if _, ok := packNameMap[pkList[0]]; ok {
							versionList := strings.Split(packNameMap[pkList[0]], ",")
							verExist := false
							for _, vl := range versionList {
								if vl == pkList[1] {
									verExist = true
									break
								}
							}
							if !verExist {
								packNameMap[pkList[0]] += "," + pkList[1]
							}
						} else {
							packNameMap[pkList[0]] = pkList[1]
						}
					}
				}
			}
		}
		for key, value := range packNameMap {
			if key != "" && len(key) > 1 {
				pkList := []string{}
				pkList = append(pkList, key)
				versionList := make([]string, 0)
				if value != "" && len(value) > 0 {
					versionList = strings.Split(value, ",")
					if len(versionList) > 0 {
						_, ok := common.FindSliceEm(versionList, packageVersion)
						if key == packageName && ok {
							cveRes, cveOk := models.QueryCveByNum(ou.CveNum, repoName, packageName, organizationID)
							if cveOk && cveRes.Status == 12 {
								continue
							}
							if cveOk && cveRes.Status == 2 {
								ics := models.IssueCommunityStatistics{CveId: cveRes.CveId,
									CveNum: cveRes.CveNum, Repo: repoName, PackageName: packageName,
									Version: value, ExistFlag: organizationID, CreateTime: common.GetCurTime()}
								num, inErr := models.InsertIssueCommunityStatistics(&ics)
								if num == 0 {
									logs.Error("InsertIssueCommunityStatistics, inErr: ", inErr, num)
								}
							} else {
								ou.Status = 1
								upErr := models.UpdateOriginUpstream(&ou, "Status")
								if upErr != nil {
									logs.Error("UpdateOriginUpstream, upErr: ", upErr)
								}
							}
						}
					}
				}
			}
		}
	}
}

func GiteePostFreshToken(refreshToken string, giteeToken *GiteeTokenInfo) {
	url := fmt.Sprintf(`https://gitee.com/oauth/token?grant_type=refresh_token`)
	param := fmt.Sprintf(`{"refresh_token": "%s"}`, refreshToken)
	res, err := util.HTTPPost(url, param)
	if err != nil {
		logs.Error(err)
		return
	}
	logs.Info("Access token result of request code cloud:", res)
	GiteeConstructor(res, giteeToken)
}

func GiteeConstructor(res map[string]interface{}, giteeToken *GiteeTokenInfo) {
	if _, ok := res["access_token"]; ok {
		giteeToken.AccessToken = res["access_token"].(string)
		giteeToken.TokenType = res["token_type"].(string)
		giteeToken.RefreshToken = res["refresh_token"].(string)
		giteeToken.Scope = res["scope"].(string)
		giteeToken.ExpiresIn = int64(res["expires_in"].(float64))
		giteeToken.CreatedAt = int64(res["created_at"].(float64))
	}
}

func GetEntIssueDetail(cve models.VulnCenter, its *models.IssueTemplate, priority *int) {
	owner, accessToken := common.GetOwnerAndToken(cve.CveNum, cve.OrganizationID)
	if cve.OrganizationID == 2 {
		if len(cve.PackName) < 2 {
			cve.PackName = beego.AppConfig.String("opengauss::gauss_issue_path")
		}
	}
	issueErr, issueBody := GetGiteeIssue(accessToken, owner, cve.PackName, its.IssueNum)
	if issueErr != nil {
		logs.Error("issue is empty, err: ", issueErr, "IssueNum: ", its.IssueNum)
		return
	} else {
		if cve.OrganizationID == 3 && issueBody != nil && issueBody["priority"] != nil {
			if p, ok := issueBody["priority"]; ok {
				if pri, ok1 := p.(float64); ok1 {
					*priority = int(pri)
				}
			}
		}
		if issueBody != nil && issueBody["plan_started_at"] != nil {
			if planAt, ok := issueBody["plan_started_at"]; !ok || planAt == nil {
				logs.Error("plan_started_at is empty, err: ", ok, "IssueNum: ", its.IssueNum)
				return
			}
			its.PlanStarted = issueBody["plan_started_at"].(string)
		}
		if issueBody != nil && issueBody["deadline"] != nil {
			if deadLine, ok := issueBody["deadline"]; !ok || deadLine == nil {
				logs.Error("deadLine is empty, err: ", ok, "IssueNum: ", its.IssueNum)
				return
			}
			its.Deadline = issueBody["deadline"].(string)
		}
	}
}

func UpdateEntIssueDetail(enterpriseId, issueId int64, token, planAt, deadLine string, priority int) {
	url := fmt.Sprintf("https://api.gitee.com/enterprises/%v/issues/%v",
		enterpriseId, issueId)
	requestBody := fmt.Sprintf(`{
			"access_token": "%s",
			"plan_started_at": "%s", 
			"deadline": "%s",
			"priority": "%v"
			}`, token, planAt, deadLine, priority)
	resp, err := util.HTTPPutMap(url, requestBody)
	if err != nil {
		logs.Error("UpdateEntIssueDetail, Update issue failed, issueId: ",
			issueId, ",err: ", err)
		return
	}
	if _, ok := resp["id"]; !ok {
		logs.Error("UpdateEntIssueDetail, Update issue failed, err: ", ok, ", issueId: ", issueId)
		return
	}
}
